home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Language/OS - Multiplatform Resource Library
/
LANGUAGE OS.iso
/
et
/
et3_0-a1.lha
/
et3
/
src
/
Rectangle.C
< prev
next >
Wrap
C/C++ Source or Header
|
1992-04-27
|
8KB
|
369 lines
#ifdef __GNUG__
#pragma implementation
#endif
#include "Rectangle.h"
#include "Class.h"
#include "Error.h"
#include "Math.h"
#include "String.h"
const Rectangle gRect0;
SimpleMetaImpl(Rectangle)
{
len= len;
if (! isptr)
sprintf(buf, "%s", ((Rectangle*) addr)->AsString());
}
Rectangle::Rectangle()
{
origin.x= origin.y= extent.x= extent.y= 0;
}
Rectangle::Rectangle(int x, int y, int w, int h)
{
origin.x= x;
origin.y= y;
extent.x= w;
extent.y= h;
}
Rectangle::Rectangle(Point o, Point e)
{
origin= o;
extent= e;
}
Rectangle::Rectangle(Point e)
{
origin= 0;
extent= e;
}
Rectangle::Rectangle(int w, int h)
{
origin.x= origin.y= 0;
extent.x= w;
extent.y= h;
}
Rectangle::Rectangle(const Rectangle &r)
{
origin.x= r.origin.x;
origin.y= r.origin.y;
extent.x= r.extent.x;
extent.y= r.extent.y;
}
Rectangle NormRect(Point p1, Point p2)
{
Rectangle r;
r.origin.x= Math::Min(p1.x, p2.x);
r.origin.y= Math::Min(p1.y, p2.y);
r.extent.x= Math::Max(p1.x, p2.x)+1-r.origin.x;
r.extent.y= Math::Max(p1.y, p2.y)+1-r.origin.y;
return r;
}
bool Rectangle::Intersects(const Rectangle &r) const
{
return origin.x < r.origin.x + r.extent.x
&& r.origin.x < origin.x + extent.x
&& origin.y < r.origin.y + r.extent.y
&& r.origin.y < origin.y + extent.y;
}
bool Rectangle::ContainsRect(const Rectangle &r) const
{
Point c1= origin + extent, c2= r.origin + r.extent;
return origin.x <= r.origin.x && c1.x >= c2.x
&& origin.y <= r.origin.y && c1.y >= c2.y;
}
bool Rectangle::OvalContainsRect(const Rectangle &r) const
{
int rad= Math::Min(extent.x, extent.y)/2;
Point c= Center();
if (Length(r.NW()-c) >= rad)
return FALSE;
if (Length(r.NE()-c) >= rad)
return FALSE;
if (Length(r.SW()-c) >= rad)
return FALSE;
if (Length(r.SE()-c) >= rad)
return FALSE;
return TRUE;
}
Rectangle Rectangle::Merge(const Rectangle &r)
{
register int x1, x2, y1, y2;
if (IsEmpty())
return *this= r;
if (r.IsEmpty())
return *this;
x1= origin.x + extent.x;
y1= origin.y + extent.y;
x2= r.origin.x + r.extent.x;
y2= r.origin.y + r.extent.y;
origin.x= Math::Min(origin.x, r.origin.x);
origin.y= Math::Min(origin.y, r.origin.y);
extent.x= Math::Max(x1, x2) - origin.x;
extent.y= Math::Max(y1, y2) - origin.y;
return *this;
}
Rectangle Union(const Rectangle &r1, const Rectangle &r2)
{
Rectangle rr= r1;
return rr.Merge(r2);
}
bool Rectangle::Clip(const Rectangle &r)
{
register int p1x, p1y, p2x, p2y;
if (IsEmpty())
return FALSE;
if (r.IsEmpty()) {
*this= gRect0; // g++ 1.37.2.beta bug on 68020 cpu ?
return FALSE;
}
p1x= origin.x + extent.x;
p1y= origin.y + extent.y;
p2x= r.origin.x + r.extent.x;
p2y= r.origin.y + r.extent.y;
origin.x= Math::Max(origin.x, r.origin.x);
origin.y= Math::Max(origin.y, r.origin.y);
extent.x= Math::Min(p1x, p2x) - origin.x;
extent.y= Math::Min(p1y, p2y) - origin.y;
return IsNotEmpty();
}
Rectangle Inter(Rectangle r1, const Rectangle &r2)
{
r1.Clip(r2);
return r1;
}
Rectangle Rectangle::Intersect(const Rectangle &r)
{
Clip(r);
return *this;
}
Rectangle BoundingBox(int npts, Point *pts, Point *np)
{
Point mi= pts[0], ma= pts[0];
Rectangle r;
register int i;
if (np == 0)
np= pts;
for (i= 1; i<npts; i++) {
mi= Min(mi, pts[i]);
ma= Max(ma, pts[i]);
}
r.origin= mi;
r.extent= ma-mi+1;
for (i= 0; i<npts; i++)
np[i]= pts[i]-mi;
return r;
}
Rectangle Rectangle::WedgeBBox(int s, int d)
{
Point mi, ma, p;
register int i;
if (d >= 270)
return *this;
mi= ma= Center();
p= AngleToPoint(s);
mi= Min(p, mi);
ma= Max(p, ma);
i= 1;
for (i= 1; i < d-1; i++) {
switch (s+i) {
case 0:
mi.y= origin.y;
break;
case 90:
ma.x= origin.x + extent.x;
break;
case 180:
ma.y= origin.y + extent.y;
break;
case 270:
mi.x= origin.x;
break;
default:
continue;
}
}
p= AngleToPoint(s+d);
return NormRect(Min(p, mi), Max(p, ma));
}
int Difference(Rectangle *rp, const Rectangle &r1, const Rectangle &ra)
{
register int p2x, p2y;
Rectangle r2, dr[4];
int n, i;
r2= Inter(r1, ra);
if (r2.IsNotEmpty()) {
p2x= r2.origin.x+r2.extent.x;
p2y= r2.origin.y+r2.extent.y;
dr[0].origin= r1.origin;
dr[0].extent.x= r1.extent.x;
dr[0].extent.y= r2.origin.y-r1.origin.y;
dr[1].origin.x= r1.origin.x;
dr[1].origin.y= r2.origin.y;
dr[1].extent.x= r2.origin.x-r1.origin.x;
dr[1].extent.y= r2.extent.y;
dr[2].origin.x= p2x;
dr[2].origin.y= r2.origin.y;
dr[2].extent.x= r1.origin.x+r1.extent.x-p2x;
dr[2].extent.y= r2.extent.y;
dr[3].origin.x= r1.origin.x;
dr[3].origin.y= p2y;
dr[3].extent.x= r1.extent.x;
dr[3].extent.y= r1.origin.y+r1.extent.y-p2y;
} else
dr[0]= r1;
for (n= i= 0; i<4; i++)
if (dr[i].IsNotEmpty())
rp[n++]= dr[i];
return n;
}
Rectangle Rectangle::Inset(Point p)
{
Rectangle r;
r.origin.x= origin.x + p.x;
r.origin.y= origin.y + p.y;
r.extent.x= extent.x - 2 * p.x;
r.extent.y= extent.y - 2 * p.y;
return r;
}
Rectangle Rectangle::Expand(Point p)
{
Rectangle r;
r.origin.x= origin.x - p.x;
r.origin.y= origin.y - p.y;
r.extent.x= extent.x + 2 * p.x;
r.extent.y= extent.y + 2 * p.y;
return r;
}
Point Rectangle::Constrain(Point p)
{
p= Min(p, origin+extent);
return Max(p, origin);
}
Point ConstrainMoveRect(const Rectangle &r1, const Rectangle &r2, Point delta)
{
Point p= r1.origin + r1.extent - r2.extent;
p= Min(p, r2.origin+delta);
return Max(r1.origin, p)-r2.origin;
}
Point Rectangle::AmountToTranslateWithin(const Rectangle &r)
{
Point delta(0), rUL= NW(), rLR= SE(), vrUL= r.NW(), vrLR= r.SE();
for (int v= 0; v <= 1; v++) {
if (rUL[v] < vrUL[v] && rLR[v] > vrLR[v])
continue;
if (rLR[v] - vrUL[v] < extent[v])
delta[v]= vrUL[v] - rUL[v];
if (vrLR[v] - rUL[v] < extent[v])
delta[v]= vrLR[v] - rLR[v];
}
return delta;
}
OStream& operator<< (OStream &s, const Rectangle &r)
{
return s << r.origin << r.extent;
}
IStream& operator>> (IStream &s, Rectangle &r)
{
return s >> r.origin >> r.extent;
}
int Rectangle::PointToAngle(Point p) const
{
p-= Center();
return (int) Math::Atan2(p.y*extent.x, p.x*extent.y);
}
Point Rectangle::OvalAngleToPoint(int ang) const
{
return Center() + PolarToPoint(ang, extent.x/2, extent.y/2);
}
Point Rectangle::AngleToPoint(int a) const
{
double si, co;
register int x= 0, y= 0;
Math::Sincos(a, &si, &co);
if (si != 0.0) {
x= (int) ((1.0 + co/Math::Abs(si))/2.0 * extent.x);
x= Math::Range(0, extent.x, x);
} else if (co >= 0.0)
x= extent.x;
if (co != 0.0) {
y= (int) ((1.0 + si/Math::Abs(co))/2.0 * extent.y);
y= Math::Range(0, extent.y, y);
} else if (si >= 0.0)
y= extent.y;
return origin + Point(x, y);
}
// Corners:
// 7|0|1
// -------
// 6| |2
// -------
// 5|4|3
int Rectangle::PointToCorner(Point p) const
{
return ((PointToAngle(p)+22)/45) % 8;
}
Point Rectangle::CornerToPoint(int n) const
{
return AngleToPoint((n % 8)*45);
}
char *Rectangle::AsString() const
{
return form("x: %d y: %d w: %d h: %d", origin.x, origin.y, extent.x, extent.y);
}